package com.shuwen.gcdj.service.api;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shuwen.gcdj.common.enums.LogModuleEnum;
import com.shuwen.gcdj.common.enums.LogTypeEnum;
import com.shuwen.gcdj.common.exception.ApiException;
import com.shuwen.gcdj.bean.AddResp;
import com.shuwen.gcdj.bean.api.request.AddApiReq;
import com.shuwen.gcdj.bean.api.request.GetApiListReq;
import com.shuwen.gcdj.bean.api.request.UpdateApiReq;
import com.shuwen.gcdj.bean.api.response.ApiItemResp;
import com.shuwen.gcdj.common.constant.Constants;
import com.shuwen.gcdj.common.enums.ErrorCode;
import com.shuwen.gcdj.common.sysLog.AddSysLogUtil;
import com.shuwen.gcdj.dto.account.InitUserDto;
import com.shuwen.gcdj.dto.api.CheckAddRespDto;
import com.shuwen.gcdj.dto.power.SearchPowerApiDto;
import com.shuwen.gcdj.entity.Api;
import com.shuwen.gcdj.mapper.mysql.ApiMapper;
import com.shuwen.gcdj.service.BaseService;
import com.shuwen.gcdj.service.power.PowerApiService;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
@AllArgsConstructor
@Slf4j
public class ApiService extends BaseService<ApiMapper, Api> {

    private final ApiMapper apiMapper;
    private final PowerApiService powerApiService;
    private final AddSysLogUtil addSysLogUtil;

    public Api getOneByCode(String code) {
        if (code == null || code.isEmpty()) {
            return null;
        }

        QueryWrapper<Api> q = new QueryWrapper<>();
        q.eq("`code`", code);
        q.eq(Constants.FIELD_KEY_IS_DELETE, Constants.IS_DELETE_NORMAL);
        q.last("limit 1");
        return getOne(q);
    }

    /**
     * 添加接口
     *
     * @param req         AddRoleReq
     * @param initUserDto InitUserDto
     * @return AddResp
     */
    public AddResp createApi(AddApiReq req, InitUserDto initUserDto) {
        // check add
        CheckAddRespDto check = checkAddReturn(req);
        AddResp resp = new AddResp();

        // add action
        Api r = new Api();
        if (req.getSort() != null) {
            r.setSort(req.getSort());
        }
        r.setSort(1);
        setCreateUpdateTime(r, initUserDto, 2);

        r.setParentId(req.getParentId());
        r.setName(req.getName());
        Optional.ofNullable(req.getCode()).ifPresent(r::setCode);
        Optional.ofNullable(req.getDesc()).ifPresent(r::setDesc);
        Optional.ofNullable(req.getPowerCode()).ifPresent(r::setPowerCode);
        Optional.ofNullable(req.getDesc()).ifPresent(r::setDesc);
        Optional.ofNullable(req.getUri()).ifPresent(r::setUri);
        Optional.ofNullable(req.getSort()).ifPresent(r::setSort);
        r.setLevel(check.getAddLevel());

        // 编辑已有同名接口
        if (check.getAddType().equals(Constants.ADD_TYPE_WITH_UPDATE)) {
            r.setId(check.getCurrentApi().getId());
            r.setIsDelete(Constants.IS_DELETE_NORMAL);
            r.setUpdateTime(null);
            updateById(r);
            addSysLogUtil.addLog(initUserDto, LogTypeEnum.LOG_TYPE_UPDATE.getTypeNum(), LogModuleEnum.LOG_MODULE_API.getModuleNum(),"编辑已有同名接口"+r.getCode(),req);
            resp.setId(check.getCurrentApi().getId());
            return resp;
        }

        // 新增接口
        setCreateUpdateTime(r, initUserDto, 1);

        boolean addRes = save(r);
        if (addRes) {
            addSysLogUtil.addLog(initUserDto,LogTypeEnum.LOG_TYPE_ADD.getTypeNum(),LogModuleEnum.LOG_MODULE_API.getModuleNum(),"添加了一个api"+r.getCode(),req);
            resp.setId(r.getId());
            return resp;
        }
        log.error("ApiService.createApi.save({}) error", r);
        return null;
    }

    private void setCreateUpdateTime(Api api, InitUserDto initUserDto, Integer type) {
        if (api == null) {
            return;
        }

        if (initUserDto != null && initUserDto.getUserId() != null && !initUserDto.getUserId().isEmpty()) {
            if (type == 1) {
                api.setCreateId(initUserDto.getUserId());
            }

            if (type == 2) {
                api.setUpdateId(initUserDto.getUserId());
            }

            if (type == 3) {
                api.setCreateId(initUserDto.getUserId());
                api.setUpdateId(initUserDto.getUserId());
            }
        }
    }

    /**
     * 修改接口
     *
     * @param req         UpdateRoleReq
     * @param initUserDto InitUserDto
     */
    public void updateApi(UpdateApiReq req, InitUserDto initUserDto) {
        if (req == null || req.getId() == null || req.getId().length() == 0) {
            throw new ApiException("接口ID不能为空");
        }

        Api api = getById(req.getId());
        if (api == null) {
            throw new ApiException("修改接口不存在");
        }
        setCreateUpdateTime(api, initUserDto, 2);

        BeanUtils.copyProperties(req, api);
        api.setUpdateTime(null);
        updateById(api);
    }

    /**
     * 删除接口
     *
     * @param apiId       String
     * @param initUserDto InitUserDto
     */
    public ErrorCode deleteApi(String apiId, InitUserDto initUserDto) {
        if(null == apiId || apiId.length()<1){
           throw  new ApiException("apiId不能为空！");
        }
        ArrayList<String> strings = new ArrayList<>();
        String[] split = apiId.split(",");
        for (String s : split){
            Api one = getById(s);
            if (one == null) {
                return ErrorCode.DATA_NOT_EXIST;
            }

            List<Api> apis = searchCurrentAndSubApi(Lists.newArrayList(s));
            log.info("deleteApi.searchCurrentAndSubApi() apis = {}", apis);

            if (apis != null && !apis.isEmpty()) {
                if (apis.size() > 1) {
                    log.error("ApiService.deleteApi(apiId = {}), apis = {}, 包含子Api，不能删除选中的Api", s, apis);
                    return ErrorCode.API_HAS_SUB_CHILDREN;
                }
                one.setIsDelete(Constants.IS_DELETE_YES);
                if (initUserDto != null && initUserDto.getUserId() != null) {
                    one.setUpdateId(initUserDto.getUserId());
                }

                // 删除接口
                apiMapper.deleteById(s);
                strings.add(one.getCode());
                // 删除权限Api关系
                SearchPowerApiDto searchPowerApiDto = new SearchPowerApiDto();
                searchPowerApiDto.setApiCodes(Lists.newArrayList(one.getCode()));
                powerApiService.deletePowerApi(searchPowerApiDto, initUserDto);
            }

        }
        addSysLogUtil.addLog(initUserDto, LogTypeEnum.LOG_TYPE_DELETE.getTypeNum(), LogModuleEnum.LOG_MODULE_API.getModuleNum(), "删除了API"+strings.toString(),apiId);

        return ErrorCode.SUCCESS;
    }


    /**
     * 获取当前接口 + 子集接口
     *
     * @param parentId List<String>
     * @return List<Role>
     */
    public List<Api> searchCurrentAndSubApi(List<String> parentId) {
        List<Api> c = new ArrayList<>();
        if (parentId == null || parentId.isEmpty()) {
            return c;
        }

        QueryWrapper<Api> qw = new QueryWrapper<>();
        qw.in("id", parentId);
        qw.eq(Constants.FIELD_KEY_IS_DELETE, Constants.IS_DELETE_NORMAL);
        c = apiMapper.selectList(qw);
        if (c == null) {
            c = new ArrayList<>();
        }

        searchSubApi(parentId, c);
        return c;
    }


    /**
     * 递归调用获取子集接口
     *
     * @param parentId List<String>
     */
    public void searchSubApi(List<String> parentId, List<Api> c) {
        if (parentId == null || parentId.isEmpty()) {
            return;
        }

        QueryWrapper<Api> qw = new QueryWrapper<>();
        qw.in("parent_id", parentId);
        qw.eq(Constants.FIELD_KEY_IS_DELETE, Constants.IS_DELETE_NORMAL);
        List<Api> roles = apiMapper.selectList(qw);
        if (roles != null) {
            List<String> newParentId = new ArrayList<>();
            for (Api api : roles) {
                newParentId.add(api.getId());
            }
            c.addAll(roles);
            searchSubApi(newParentId, c);
        }
    }

    private CheckAddRespDto checkAddReturn(AddApiReq req) {
        if (req.getName() == null || req.getName().length() == 0) {
            throw new ApiException("接口名不能为空");
        }

        CheckAddRespDto dto = new CheckAddRespDto();
        dto.setAddLevel(1);
        if (req.getParentId() == null) {
            req.setParentId("");
        }

        if (!req.getParentId().equals("")) {
            Api parent = getById(req.getParentId());
            Optional.ofNullable(parent).ifPresent(dto::setParentApi);
            if (parent != null && parent.getLevel() != null) {
                dto.setAddLevel(parent.getLevel() + 1);
            }
        }

        QueryWrapper<Api> q = new QueryWrapper<>();
        q.eq("parent_id", req.getParentId());
        q.eq("name", req.getName());
        Api api = getOne(q);
        if (api != null) {
            if (api.getIsDelete().equals(Constants.IS_DELETE_NORMAL)) {
                throw new ApiException("同一层级接口名已存在");
            }

            dto.setCurrentApi(api);
            dto.setAddType(Constants.ADD_TYPE_WITH_UPDATE);
            return dto;
        }

        // 正常添加
        dto.setAddType(Constants.ADD_TYPE_NORMAL_ADD);
        return dto;
    }

    /**
     * 获取所有api
     *
     * @return List<ApiItemResp>
     */
    public List<ApiItemResp> searchList(GetApiListReq req) {
        return apiMapper.searchList(req);
    }
}

